home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
EnigmA Amiga Run 1999 March
/
EnigmA AMIGA RUN 35 (1999)(G.R. Edizioni)(IT)[!][issue 1999-03].iso
/
earcd
/
-archivi
/
-recent2
/
amhelios.lha
/
AmHelios
/
prog_rad.cpp
< prev
next >
Wrap
C/C++ Source or Header
|
1997-08-31
|
11KB
|
394 lines
////////////////////////////////////////////////////////////
//
// PROG_RAD.CPP - Progressive Refinement Radiosity Class
//
// Version: 1.03A
//
// History: 94/08/23 - Version 1.00A release.
// 94/09/24 - Modified Open function.
// 94/11/26 - Added Interpolate function.
// - Modified Close, Calculate,
// AddAmbient and CalcOverShoot
// functions.
// 94/12/16 - Version 1.01A release.
// 95/02/05 - Version 1.02A release.
// 95/07/16 - Removed ambient exitance addition
// from Calculate function.
// - Added ambient exitance addition
// to Close function.
// 95/07/21 - Version 1.02B release.
// 96/02/14 - Version 1.02C release.
// 96/04/01 - Version 1.03A release.
//
// Compilers: Microsoft Visual C/C++ Professional V1.5
// Borland C++ Version 4.5
//
// Author: Ian Ashdown, P.Eng.
// byHeart Software Limited
// 620 Ballantree Road
// West Vancouver, B.C.
// Canada V7S 1W3
// Tel. (604) 922-6148
// Fax. (604) 987-7621
//
// Copyright 1994-1996 byHeart Software Limited
//
// The following source code has been derived from:
//
// Ashdown, I. 1994. Radiosity: A Programmer's
// Perspective. New York, NY: John Wiley & Sons.
//
// It may be freely copied, redistributed, and/or modified
// for personal use ONLY, as long as the copyright notice
// is included with all source code files.
//
////////////////////////////////////////////////////////////
#include "prog_rad.h"
// Open progressive radiosity renderer
BOOL ProgRad::Open( Environ *pe )
{
penv = pe; // Save environment pointer
step_count = 0; // Reset step count
convergence = 1.0; // Convergence
start = clock(); // Initialize start time
InitExitance(); // Initialize exitances
if (amb_flag == TRUE) // Ambient exitance required ?
{
CalcInterReflect(); // Calculate interreflection factor
CalcAmbient(); // Calculate initial ambient term
}
// Allocate form factor array
if ((ff_array = new float[penv->GetNumElem()]) == NULL)
return FALSE;
return TRUE;
}
// Close progressive radiosity renderer
void ProgRad::Close()
{
// Release form factor array
if (ff_array != NULL)
{
delete [] ff_array;
ff_array = NULL;
}
if (penv != NULL)
{
// if (amb_flag == TRUE)
// {
// AddAmbient(); // Add ambient exitance
// }
Interpolate(); // Interpolate vertex exitances
AddEmittance(); // Add parent surface emittances
}
}
// Snapshot current radiosity render state
void ProgRad::Snapshot()
{
if (penv != NULL)
{
// if (amb_flag == TRUE)
// {
// AddAmbient(); // Add ambient exitance
// }
Interpolate(); // Interpolate vertex exitances
AddEmittance(); // Add parent surface emittances
}
}
// Calculate element exitances
BOOL ProgRad::Calculate()
{
float rff; // Reciprocal form factor
BOOL self; // Self patch flag
WORD ff_index = 0; // Form factor array index
Element3 *pelem; // Element pointer
Instance *pinst; // Instance pointer
Patch3 *ppatch; // Patch pointer
Surface3 *psurf; // Surface pointer
Spectra delta; // Delta exitance
Spectra reflect; // Surface reflectance
Spectra shoot; // Shoot exitance
// Check for maximum number of steps
if (step_count >= max_step)
return TRUE;
UpdateUnsentStats(); // Update unsent flux statistics
// Check for convergence
if (convergence < stop_criterion)
return TRUE;
// Calculate form factors
ffd.CalcFormFactors(pmax, penv->GetInstPtr(), ff_array,
penv->GetNumElem());
if (over_flag == TRUE)
{
CalcOverShoot(); // Calculate overshooting parameters
}
// Walk the instance list
pinst = penv->GetInstPtr();
while (pinst != NULL)
{
// Walk the surface list
psurf = pinst->GetSurfPtr();
while (psurf != NULL)
{
// Get surface reflectance
reflect = psurf->GetReflectance();
// Walk the patch list
ppatch = psurf->GetPatchPtr();
while (ppatch != NULL)
{
// Check for self patch
self = (BOOL)((ppatch == pmax) ? TRUE : FALSE);
// Walk the element list
pelem = ppatch->GetElementPtr();
while (pelem != NULL)
{
if (self == FALSE) // Ignore self
{
// Check element visibility
if (ff_array[ff_index] > 0.0)
{
// Compute reciprocal form factor
rff = (float) min((double) ff_array[ff_index]
* pmax->GetArea() / pelem->GetArea(),
1.0);
// Get shooting patch unsent exitance
shoot = pmax->GetExitance();
if (over_flag == TRUE)
{
// Add overshoot exitance
shoot.Add(overshoot);
}
// Calculate delta exitance
delta = Mult(reflect, shoot);
delta.Scale(rff);
// Update element exitance
pelem->GetExitance().Add(delta);
// Update patch unsent exitance
delta.Scale(pelem->GetArea() /
ppatch->GetArea());
ppatch->GetExitance().Add(delta);
}
}
pelem = pelem->GetNext();
ff_index++;
}
ppatch = ppatch->GetNext();
}
psurf = psurf->GetNext();
}
pinst = pinst->GetNext();
}
if (over_flag == TRUE)
{
// Subtract shot exitance from patch unsent exitance
pmax->GetExitance().Subtract(shoot);
}
else
{
// Reset unsent exitance to zero
pmax->GetExitance().Reset();
}
if (amb_flag == TRUE)
{
CalcAmbient(); // Recalculate ambient exitance
}
step_count++; // Increment step count
return FALSE; // Convergence not achieved yet
}
// Interpolate vertex reflected exitances
void ProgRad::Interpolate()
{
int num_elem; // Number of elements
Element3 *pelem; // Element pointer
ElemList *pel; // Element list pointer
Instance *pinst; // Instance pointer
Vertex3 *pvert; // Vertex pointer
Spectra exitance; // Vertex exitance
Spectra reflect; // Surface reflectance
Spectra delta_amb; // Delta ambient exitance
// Walk the instance list
pinst = penv->GetInstPtr();
while (pinst != NULL)
{
// Walk the vertex list
pvert = pinst->GetVertPtr();
while (pvert != NULL)
{
// Initialize vertex reflected exitance
pvert->GetExitance().Reset();
// Walk the element list
pel = pvert->GetElemListPtr();
num_elem = 0;
while (pel != NULL)
{
// Get the element pointer
pelem = pel->GetElemPtr();
exitance = pelem->GetExitance();
reflect = pelem->GetParentPtr()->GetParentPtr()->GetReflectance();
if(amb_flag == TRUE)
{
delta_amb = Mult(ambient, reflect);
exitance.Add(delta_amb);
}
// Add element reflected exitance
pvert->GetExitance().Add(exitance);
pel = pel->GetNext();
num_elem++;
}
// Scale vertex reflected exitance according to number
// of shared elements
pvert->GetExitance().Scale(1.0 / (double) num_elem);
pvert = pvert->GetNext();
}
pinst = pinst->GetNext();
}
}
void ProgRad::AddAmbient() // Add ambient exitance
{
Element3 *pelem; // Element pointer
Instance *pinst; // Instance pointer
Patch3 *ppatch; // Patch pointer
Spectra delta_amb; // Delta ambient exitance
Spectra reflect; // Surface reflectance
Surface3 *psurf; // Surface pointer
// Walk the instance list
pinst = penv->GetInstPtr();
while (pinst != NULL)
{
// Walk the surface list
psurf = pinst->GetSurfPtr();
while (psurf != NULL)
{
// Get surface reflectance
reflect = psurf->GetReflectance();
// Walk the patch list
ppatch = psurf->GetPatchPtr();
while (ppatch != NULL)
{
// Walk the element list
pelem = ppatch->GetElementPtr();
while (pelem != NULL)
{
// Calculate delta ambient exitance
delta_amb = Mult(ambient, reflect);
// Update element exitance
pelem->GetExitance().Add(delta_amb);
pelem = pelem->GetNext();
}
ppatch = ppatch->GetNext();
}
psurf = psurf->GetNext();
}
pinst = pinst->GetNext();
}
}
// Calculate overshooting parameters
void ProgRad::CalcOverShoot()
{
BOOL self; // Self patch flag
WORD ff_index = 0; // Form factor array index
Element3 *pelem; // Element pointer
Instance *pinst; // Instance pointer
Patch3 *ppatch; // Patch pointer
Spectra spr; // Shooting patch reflectance
Spectra unsent; // Patch unsent exitance
Surface3 *psurf; // Surface pointer
overshoot.Reset(); // Reset overshooting parameters
// Walk the instance list
pinst = penv->GetInstPtr();
while (pinst != NULL)
{
// Walk the surface list
psurf = pinst->GetSurfPtr();
while (psurf != NULL)
{
// Walk the patch list
ppatch = psurf->GetPatchPtr();
while (ppatch != NULL)
{
// Check for self patch
self = (BOOL)((ppatch == pmax) ? TRUE : FALSE);
// Walk the element list
pelem = ppatch->GetElementPtr();
while (pelem != NULL)
{
if (self == FALSE) // Ignore self
{
// Get unsent patch exitance
unsent = ppatch->GetExitance();
// Limit unsent exitance to positive color band
// values
unsent.Limit();
// Multiply unsent exitance by patch-to-
// element form factor
unsent.Scale(ff_array[ff_index]);
// Update overshooting parameters
overshoot.Add(unsent);
}
pelem = pelem->GetNext();
ff_index++;
}
ppatch = ppatch->GetNext();
}
psurf = psurf->GetNext();
}
pinst = pinst->GetNext();
}
// Get shooting patch reflectance
spr = pmax->GetParentPtr()->GetReflectance();
// Multiply overshooting parameters by shooting patch
// reflectance
overshoot.Mult(spr);
}